# coding=utf-8
import os
import struct
import sys
import socket
import copy
#系统64位还是32位判定
import platform

#协议封装
class bsp:
	def __init__(self):
		self.pase_str = ""
		self.hash_obj ={}
	def _get_type_len(self,type):
		#print "type:%s" % (type)
		bsp_pack_type={
				0x1:1,
				0x2:2,
				0x3:4,
				0x4:8,
				0x5:8,
				0x6:4,
				0xf0:0,
				0xf1:0 
				}
		return bsp_pack_type.get(type,"")
		
	def _get_type(self):
		temp_type = struct.unpack('B',self.pase_str[0:1])[0]
		self.pase_str = self.pase_str[1:]
		#print "type after len:%s" % (len(self.pase_str))
		return temp_type
	def _get_value(self):
		key_type = self._get_type()
		key_len = self._get_type_len(key_type)
		#print "type len:%s" % (key_len)
		if key_len == "":
			print "pase error!"
			sys.exit()
		if key_type == 0x1:
			temp = struct.unpack('B',self.pase_str[0:key_len])[0]
			self.pase_str = self.pase_str[key_len:]
		elif key_type ==0x2:
			temp = struct.unpack('!H',self.pase_str[0:key_len])[0]
			#temp = socket.ntohs(temp)
			self.pase_str = self.pase_str[key_len:]
		elif key_type ==0x3:
			temp = struct.unpack('!I',self.pase_str[0:key_len])[0]
			#temp = socket.ntohs(temp)
			self.pase_str = self.pase_str[key_len:]
		elif key_type ==0xf0:
			temp = "{"
		elif key_type ==0xf1:
			temp = "}"
		elif key_type ==0x6:
			str_len = struct.unpack('!I',self.pase_str[0:key_len])[0]
			self.pase_str = self.pase_str[key_len:]
			#str_len = socket.ntohl(str_len)
			#print str_len
			#sys.exit()
			pf = "%ds" % str_len
			temp = struct.unpack(pf,self.pase_str[0:str_len])[0]
			self.pase_str = self.pase_str[str_len:]
		elif key_type == 0x5:
			temp = struct.unpack('d',self.pase_str[0:key_len])[0]
			self.pase_str = self.pase_str[key_len:]
		elif key_type == 0x4:
			#print "here!"
			#sys.exit()
			temp = struct.unpack('!Q',self.pase_str[0:key_len])[0]
			#print temp
			self.pase_str = self.pase_str[key_len:]
		else:
			#print key_type
			sys.exit()
		#print "type value:%s" % (temp)
		#sys.exit()
		return temp
	def pase_dict(self,obj,key_list):
		cur_obj = obj
		for i in key_list:
			cur_obj = cur_obj[i]
		while len(self.pase_str)>0:
			temp_key = self._get_value()
			if temp_key =="}":
				key_list.pop()
				return cur_obj
			else:
				sub_value = self._get_value()
				if sub_value=="{":
					cur_obj[temp_key] = {}
					key_list.append(temp_key)
					self.pase_dict(obj,key_list)
					
				else:
					cur_obj[temp_key] = sub_value
	def unpack(self, pase_str):
		self.pase_str = pase_str
		temp = []
		while len(self.pase_str)>0:
			temp_key = self._get_value()
			if len(self.pase_str)>0:
				temp_value = self._get_value()
			
			if temp_value == "{":
				self.hash_obj[temp_key]={}
				self.pase_dict(self.hash_obj,[temp_key])
			else:
				self.hash_obj[temp_key] = temp_value
		return self.hash_obj
	def _list_to_dict(self,param_list):
		temp = {}
		for i in xrange(len(param_list)):
			temp[i] = param_list[i]
		return temp

	def _pack_type(self,p_type):
			return struct.pack("B",p_type)

	def _pack_short(self,param_short):
		return self._pack_type(0x2)+struct.pack("!H",param_short)

	def _pack_int(self,param_int):
		return self._pack_type(0x3)+struct.pack('!I',param_int)
	
	def _pack_long(self,param_float):
		return self._pack_type(0x4)+struct.pack("!Q",param_float)
	
	def _pack_double(self,param_double):
		return self._pack_type(0x5)+struct.pack("d",param_double)

	def _pack_str(self,param_str):
		temp = self._pack_type(0x6)
		temp += struct.pack('!I',len(param_str))
		pf = "%ds" % len(param_str)
		temp +=struct.pack(pf,param_str)
		return temp

	def _pack_dict(self,param_dict,pack_str):
		pack_str+=self._pack_type(0xf0)
		for k,v in param_dict.items():
			if isinstance(k,int) == True:
				pack_str+= self._pack_int(k)
			elif isinstance(k,long) == True:
				pack_str+= self._pack_long(k)
			elif isinstance(k,float) == True:
				pack_str+= self._pack_double(k)
			elif isinstance(k,str) == True:
				pack_str+= self._pack_str(k)

			if isinstance(v,int) == True:
				pack_str+= self._pack_int(v)
			elif isinstance(v,long) == True:
				pack_str+= self._pack_long(v)
			elif isinstance(v,float) == True:
				pack_str+= self._pack_double(v)
			elif isinstance(v,str) == True:
				pack_str+= self._pack_str(v)
			elif isinstance(v,list) == True:
				v = self._list_to_dict(v)
				pack_str = self._pack_dict(v,pack_str)
			elif isinstance(v,dict) == True:
				pack_str = self._pack_dict(v,pack_str)
			elif isinstance(v,tuple) == True:
				pack_str = self._pack_dict(v,pack_str)
			else:
				pack_str+= self._pack_str(v)
		pack_str+=self._pack_type(0xf1)
		return pack_str

	def pack(self,param):
		pack_str = ""
		if isinstance(param,list) == True:
			param = self._list_to_dict(param)
		for k,v in param.items():
			if isinstance(k,int) == True:
				pack_str+= self._pack_int(k)
			elif isinstance(k,long) == True:
				pack_str+= self._pack_long(k)
			elif isinstance(k,float) == True:
				pack_str+= self._pack_double(k)
			elif isinstance(k,str) == True:
				pack_str+= self._pack_str(k)

			if isinstance(v,int) == True:
				pack_str+= self._pack_int(v)
			elif isinstance(v,long) == True:
				pack_str+= self._pack_long(v)
			elif isinstance(v,float) == True:
				pack_str+= self._pack_double(v)
			elif isinstance(v,str) == True:
				pack_str+= self._pack_str(v)
			elif isinstance(v,list) == True:
				v = self._list_to_dict(v)
				pack_str = self._pack_dict(v,pack_str)
			elif isinstance(v,dict) == True:
				pack_str = self._pack_dict(v,pack_str)
			elif isinstance(v,tuple) == True:
				pack_str = self._pack_dict(v,pack_str)
			else:
				pack_str+= self._pack_str(v)
			
		return pack_str

#协议的socket应用
class bsp_parser:
	def __init__(self,parser_obj,header_len=8,cmd_len=4):
		self.header_len = header_len
		self.cmd_len = cmd_len
		self.parser = parser_obj

	def get_header(self,socket_obj):
		recv_cmd = 0
		body_len = 0
		temp = {'cmd':recv_cmd,'body_len':body_len}
		try:
			header_msg = socket_obj.recv(self.header_len)
			if len(header_msg)==self.header_len:
				recv_cmd = struct.unpack('I',header_msg[0:self.cmd_len])[0]
				recv_cmd = socket.ntohl(recv_cmd)
				body_len = struct.unpack('I',header_msg[self.cmd_len:self.header_len])[0]
				body_len = socket.ntohl(body_len)
				temp = {'cmd':recv_cmd,'body_len':body_len}
		except:
			temp = {'cmd':0,'body_len':0}
		return temp
	def get_body(self,socket_obj,body_len):
		body_contents =''
		if body_len==0:
			return ""
		try:
			while len(body_contents)<body_len:
				body_contents += socket_obj.recv(body_len-len(body_contents))
		except:
			return ""
		pf = "%ds" % body_len
		if len(body_contents) != body_len or body_len==0:
			return ""
		temp = struct.unpack(pf,body_contents)[0]
		return self.parser.unpack(temp)

	def send_msg(self,socket_obj,cmd=0,send_list={}):
		content = self.parser.pack(send_list)
		cmd = socket.htonl(cmd)
		send_len_temp = len(content)
		send_len = socket.htonl(send_len_temp)
		send_temp = struct.pack('II'+str(send_len_temp)+'s',cmd,send_len,content)
		try:
			return socket_obj.send(send_temp)
		except:
			return False

	
if __name__ == '__main__':
	
	#协议的socket 使用用例
	host = "192.168.3.233"
	port = 65100
	
	#协议解析声明
	bsp_parser = bsp_parser(bsp())
	#socket连接
	cs=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	cs.settimeout(10)
	cs.connect((host, port))
	#登陆请求发送数组
	login_msg = {'user_id':1,'cookie_hash':'fd5d867d229de55b4ea34771fd06d383'}
	#发送登陆请求
	bsp_parser.send_msg(cs,10001,login_msg)
	#返回协议头解析
	header = bsp_parser.get_header(cs)
	print header
	#返回协议内容解析
	body = bsp_parser.get_body(cs,header['body_len'])
	print body
	sys.exit()


	#纯socket的协议使用用例
	send_msg = bsp.pack(login_msg)
	cmd = socket.htonl(10001)
	send_len = socket.htonl(len(send_msg))
	cs.send(pack("II"+str(len(send_msg))+"s",cmd,send_len,send_msg))
	
	header_msg = cs.recv(8)
	recv_cmd = unpack('I',header_msg[0:4])[0]
	recv_cmd = socket.ntohl(recv_cmd)
	body_len = unpack('I',header_msg[4:])[0]
	body_len = socket.ntohl(body_len)

	print "cmd:%d,body len:%d" % (recv_cmd,body_len)

	body_contents = ""
	while len(body_contents)<body_len:
		body_contents += cs.recv(body_len-len(body_contents))
	
	body_content = bsp.unpack(body_contents)
	print body_contents
	sys.exit()

	#bsp协议的使用测试
	file_contents = open("bindata-php-output.bin","rb").read()
	#temp = eval("{'sanshi':'print sanshi1'}")
	#print temp['sanshi']

	#file_contents = file_contents[8:]
	print "str len:%s" %(len(file_contents))

	bsp = bsp()
	temp_unpack = bsp.unpack(file_contents)
	print temp_unpack
	temp = bsp.pack(temp_unpack)
	#print len(temp)
	print "str len:%s" %(len(temp))
	print bsp.unpack(temp)

	file_contents = open("bindata_2.txt","rb").read()
	#temp = eval("{'sanshi':'print sanshi1'}")
	#print temp['sanshi']

	file_contents = file_contents[8:]
	print "str len:%s" %(len(file_contents))

	#bsp = bsp()
	temp_unpack = bsp.unpack(file_contents)
	print temp_unpack
	temp = bsp.pack(temp_unpack)
	#print len(temp)
	print "str len:%s" %(len(temp))
	print bsp.unpack(temp)